/**
* @file Infrasound.VDM.c
*
* @ingroup libVDM
* @brief   virtual data memory implementation for complete packets
* 
*  - packet history
*  - 512byte Blocks can be pagedto sd-card if deficient memory
* 
* @author  Andreas Schlueter <mersaultpatrice@gmail.com>
* @date    oct 2008
* @version 0.1
*/

//#define VDM_DEBUG
#define VDM_C

#include <Infrasound.VDM.h>
#include "Infrasound.VDM.internals.h"
#include <Infrasound.VDM.history.h>

#ifdef SDCARD
#include <ScatterWeb.Sd.h>
#include <ScatterWeb.Mutex.h>
#endif

/**
* Prototypes
*/
#ifdef SDCARD
void _vdm_dma_written(enum sd_write_ret ret);
void _vdm_dma_read(uint16_t ret);
void _vdm_mtx_pageout(enum mutex_dev device);
void _vdm_mtx_pagein(enum mutex_dev device);
void _vdm_update_history(sd_block_t* b, uint16_t sd_addr);
#endif


///< clears a block
#define VDM_CLEAR(b) do{ \
	b->num_frames = 0; \
	b->dirty = false; \
	b->paged = false; \
	uint8_t i; \
	for(i=0; i<NUM_FRAMES; i++){ b->frames[i].decoded.nwh.size = 0; b->frames[i].decoded.crc=0; b->frames[i].decoded.payload.seg.key.raw =0;} \
}while(0)

///< insert empty block in according vdm structure
#ifdef SENSOR
#define VDM_RESERVE do{ \
	if(!vdm_reserved){ QUEUE_GET_FIRST(pagedOutQueue, vdm_reserved); VDM_CLEAR(vdm_reserved); } \
}while(0) 
#else
#define VDM_RESERVE
#endif

/**
* globals
*/
volatile sd_block_t		vdm_buffer[NUM_RAM_BLOCKS];	///< data RAM

#ifdef SENSOR
static sd_block_t*		vdm_reserved;				///< reserved block for allocate()
#endif

QUEUE(pagedOutQueue);								///< empty and recently paged out blocks
STACK(fragmentStack);								///< partly filled blocks
STACK(pagedInStack);								///< full and recently paged in blocks

#ifdef SDCARD
static bool				multipage;					///< true, if with one page operation multiple blocks are paged
static uint16_t			sd_write_head;				///< points to next empty position on sd card
static uint16_t			sd_read_head;				///< points to next empty position on sd card
#define SD_BIT_MASK		0x3FFF						///< only 14bit addressing of 512byte blocks
static sd_block_t*		paging_block;				///< currently paged block
static uint32_t			sd_address;					///< real SD card address
#endif

extern history_entry_t	history[HISTORY_SIZE];		///< the history
/**
* initializes dma and all RAM blocks
*/
uint8_t vdm_init(){

	QUEUE_INIT(pagedOutQueue);
	STACK_INIT(fragmentStack);
	STACK_INIT(pagedInStack);

	//all other blocks are ready for requests
	uint8_t i=0;

#ifdef SENSOR
	//first block is reserved
	vdm_reserved = (sd_block_t*)&(vdm_buffer[0]);
	i = 1;
#endif

	//fill queue for empty blocks
	for(; i<NUM_RAM_BLOCKS; i++){
		if(QUEUE_FULL(pagedOutQueue)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_init:QUEUE_FULL(pagedOutQueue)\n");			
#endif
			return VDM_ERROR_OVERFLOW;
		}
		QUEUE_ADD_LAST(pagedOutQueue, (sd_block_t*)&(vdm_buffer[i]));
	}

	//init blocks
	for(i=0; i<NUM_RAM_BLOCKS; i++){
		VDM_CLEAR((&vdm_buffer[i]));
		vdm_buffer[i].locked = false;
	}

#ifdef SDCARD
	//init mutex
	//mutex_init(MUTEX_DMA);

	//sd card uart and spi initialization
	Sd_init();

	// initialize card 
	uint8_t ret;
	ret = Sd_init_card();	
	if( ret != SD_INIT_SUCCESS ){
#ifdef VDM_DEBUG
		printf("(ERR)vdm_init:sd_init_card error %d\n", ret);			
#endif
		return VDM_ERROR_SD_CARD;
	}

	//SD card empty (will be overwritten!)
	sd_write_head = 0;
	sd_read_head = 0;
#endif

	//the history
	history_init();

	return VDM_SUCCEEDED;
}

#ifdef SENSOR
/**
* @brief allocates a block
* @return a block or NULL if RAM is full
*/
sd_block_t* vdm_allocate(){

	sd_block_t* b = vdm_reserved;

	//reserve new block
	if(QUEUE_EMPTY(pagedOutQueue)){
		vdm_reserved = NULL;
#ifdef SDCARD
		vdm_pageout(true);
#endif
	}else{
		QUEUE_GET_FIRST(pagedOutQueue, vdm_reserved);
	}

	if(b){
		VDM_CLEAR(b);
		if(!(b->locked))
			b->locked = true;
#ifdef VDM_DEBUG
		else
			printf("(ERR)vdm_allocate: block locked!\n");
	}
	vdm_invariant(false);
#else
	}
#endif
	return b;
}
#endif

/**
* @brief requests an empty block
* @return an empty or partly filled block or NULL if RAM is full
*/
sd_block_t* vdm_requestBlock(){

	sd_block_t* b;
	//partly filled blocks first
	if(!(STACK_EMPTY(fragmentStack)))
		STACK_POP(fragmentStack, b);
	else if(!(QUEUE_EMPTY(pagedOutQueue))){
		QUEUE_GET_FIRST(pagedOutQueue, b);
		VDM_CLEAR(b);
	}
	else{
#ifdef VDM_DEBUG
		printf("(WARN)vdm_requestBlock:not enough memory\n");			
#endif
		b = NULL;
	}

	if(b){
		if(!(b->locked))
			b->locked = true;
#ifdef VDM_DEBUG
		else
			printf("(ERR)vdm_requestBlock: block locked!\n");
	}
	vdm_invariant(false);
#else
	}
#endif

	return b;
}

/**
* @brief a block is released to VDM. Block can be paged, after
*/
uint8_t vdm_releaseBlock(sd_block_t* b){

	//dint();

	if(!b){
#ifdef VDM_DEBUG
		printf("(ERR)vdm_releaseBlock: nullpointer\n");	
#endif
		return VDM_ERROR_NULLPOINTER;
	}

	if(b->locked)
		b->locked = false;
	else{
#ifdef VDM_DEBUG
		printf("(ERR)vdm_releaseBlock: access violation.\n");	
#endif
		return VDM_ACCESS_VIOLATION;
	}

	//full block:
	if(b->num_frames==NUM_FRAMES){
		if(STACK_FULL(pagedInStack)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_releaseBlock:STACK_FULL(pagedInStack)\n");			
#endif
			return VDM_ERROR_OVERFLOW;
		}
		STACK_PUSH(pagedInStack, b);
	//empty block:
	}else if(b->num_frames==0){
		if(QUEUE_FULL(pagedOutQueue)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_releaseBlock:QUEUE_FULL(pagedOutQueue)\n");			
#endif
			return VDM_ERROR_OVERFLOW;
		}
		QUEUE_ADD_LAST(pagedOutQueue, b);
		VDM_RESERVE;
	}
	// partly filled:
	else{
		if(STACK_FULL(fragmentStack)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_releaseBlock:STACK_FULL(fragmentStack)\n");			
#endif
			return VDM_ERROR_OVERFLOW;
		}
		STACK_PUSH(fragmentStack, b);
	}

	//update history
	if(b->dirty){
		uint8_t i;

		//find block_idx
		uint8_t block_idx=0;
		for(i=0; i<NUM_RAM_BLOCKS; i++){
			if(b == &(vdm_buffer[i])){
				block_idx = i;
				break;
			}
		}

		for(i=0; i<NUM_FRAMES; i++){
			//segment used?
			if(b->frames[i].decoded.nwh.size == 0)
				continue;
			history_entry_t* e= &(history[HASH(b->frames[i].decoded.payload.seg.key.raw)]);
			//new entry?
			if(e->id.raw != b->frames[i].decoded.payload.seg.key.raw){
				//locked?
				if(!(e->info.properties.paged) && !(e->info.properties.confirmed)){					
#ifdef VDM_DEBUG
					printf("entry info %u %u \n", ((uint16_t*)e)[0], ((uint16_t*)e)[1]);
					printf("(WARN)vdm_releaseBlock:new segment %u:%u not added to history(entry %u:%u on pos %u locked)\n", 
						b->frames[i].decoded.payload.seg.key.decoded.source_id, 
						b->frames[i].decoded.payload.seg.key.decoded.sequence_nr,
						e->id.decoded.source_id,
						e->id.decoded.sequence_nr, 
						HASH(b->frames[i].decoded.payload.seg.key.raw));			
#endif
					continue;
				}
				e->id.raw = b->frames[i].decoded.payload.seg.key.raw;
				//printf("new pkt %u:%u at b%u(%u) f%u\n\n", 
				//	e->id.decoded.source_id, 
				//	e->id.decoded.sequence_nr, 
				//	block_idx, b, i);
			}

			e->info.properties.block_idx = block_idx;
			e->info.properties.frame_idx = i;
			e->info.properties.confirmed = false;
			e->info.properties.paged = false;
		}
		b->paged = false;
		b->dirty = false;
	}

#ifdef VDM_DEBUG
	vdm_invariant(false);
#endif

	return VDM_SUCCEEDED;
}


#ifdef SDCARD
/**
* @brief all full block are paged out to SD card 
*/
void vdm_pageout(bool single){

	multipage = !single;

PAGEOUT_OPT:

	//full block available?
	if(STACK_EMPTY(pagedInStack))
		return; //nothing to pageout

	//SD card full?
	if( ((sd_write_head+1)&SD_BIT_MASK) == sd_read_head){
#ifdef VDM_DEBUG
		printf("(WARN)vdm_pageout:SD card full\n");			
#endif	
		return;
	}

	//pageout optimazation by moving the read head to the left
	STACK_POP(pagedInStack, paging_block);
	uint16_t head = (sd_read_head-1)&SD_BIT_MASK;
	if(paging_block->paged && paging_block->sd_address == head){

		if(QUEUE_FULL(pagedOutQueue) ){// error!!!
#ifdef VDM_DEBUG
			printf("(ERR)vdm_pageout:QUEUE_FULL(pagedOutQueue)\n");			
#endif			
			return;
		}
		//restore prior sd head address
		sd_read_head = head;

		//appent element on the head
		QUEUE_ADD_FIRST(pagedOutQueue, paging_block); //back on stack
#ifdef VDM_DEBUG
		printf("(INFO)vdm_pageout: block pagout optimization by moving r\n");	
#endif	
		VDM_RESERVE;

		//update history
		_vdm_update_history(paging_block, paging_block->sd_address);

		if(multipage)
			goto PAGEOUT_OPT;
		else return;
	}

	//pageout optimazation by moving the write head to the right
	if(paging_block->paged && paging_block->sd_address == sd_write_head){

		if(QUEUE_FULL(pagedOutQueue) ){// error!!!
#ifdef VDM_DEBUG
			printf("(ERR)vdm_pageout:QUEUE_FULL(pagedOutQueue)\n");			
#endif			
			return;
		}
		//restore prior sd write address
		sd_write_head = (sd_write_head+1)&SD_BIT_MASK;

		//appent element on the tail
		QUEUE_ADD_LAST(pagedOutQueue, paging_block); //back on stack
#ifdef VDM_DEBUG
		printf("(INFO)vdm_pageout: block pagout optimization by moving w\n");	
#endif	
		VDM_RESERVE;

		//update history
		_vdm_update_history(paging_block, paging_block->sd_address);

		if(multipage)
			goto PAGEOUT_OPT;
		else return;
	}

	//no optimization
	STACK_PUSH(pagedInStack, paging_block);

	mutex_lock(MUTEX_DMA, _vdm_mtx_pageout);
}

/**
* @brief callback function of mutex consumer, called when lock is possible
*/
void _vdm_mtx_pageout(enum mutex_dev device){

	enum sd_write_ret ret; 

	//full block available? (could have changed)
	if(STACK_EMPTY(pagedInStack)){
		return; //nothing to pageout
	}else{
		STACK_POP(pagedInStack, paging_block);
		sd_address = ((uint32_t)sd_write_head) << sd_state.BlockLen_bit;

		ret = Sd_write_block(sd_address, (void*)paging_block->frames, _vdm_dma_written);

		//paging error!
		if(ret != SD_WRITE_SUCCESS){
#ifdef VDM_DEBUG
			printf("(ERR)_vdm_mtx_pageout:Sd_write_block error %d\n",ret);			
#endif	


			mutex_unlock(MUTEX_DMA);
			if(!(STACK_FULL(pagedInStack)) )
				STACK_PUSH(pagedInStack, paging_block); //back on stack
#ifdef VDM_DEBUG
			else
				printf("(ERR)_vdm_mtx_pageout:STACK_FULL(pagedInStack)\n");			
#endif	
		}
	}
}

/**
* @brief function called when DMA write process finished
* @author andi
*
* @param ret result code (see enum #sd_write_ret)
*/
void _vdm_dma_written(enum sd_write_ret ret){

#ifdef VDM_DEBUG
	//printf("(INFO)_vdm_dma_written:block paged on address %d\n", sd_write_head);			
#endif	
	//temporally unlock mutex for fairness
	mutex_unlock(MUTEX_DMA);

	paging_block->dirty = false;
	paging_block->sd_address = sd_write_head;
	paging_block->paged = true;

	//check for invalid addresses:
	sd_block_t* b;
	QUEUE(temp);
	QUEUE_INIT(temp);
	while(!STACK_EMPTY(pagedInStack)){ //full blocks
		STACK_POP(pagedInStack, b);
		QUEUE_ADD_LAST(temp, b);
		if(b->sd_address == sd_write_head){
			b->paged = false;
#ifdef VDM_DEBUG
			printf("(INFO)_vdm_dma_written:block overwritten on addr %d\n", sd_write_head);			
#endif
		}
	}
	while(!QUEUE_EMPTY(temp)){//write back
		QUEUE_GET_LAST(temp, b);
		STACK_PUSH(pagedInStack, b);
	}
	while(!QUEUE_EMPTY(pagedOutQueue)){ // check "empty" blocks
		QUEUE_GET_FIRST(pagedOutQueue, b);
		QUEUE_ADD_LAST(temp, b);
		if(b->sd_address == sd_write_head){
			b->paged = false;
#ifdef VDM_DEBUG
			printf("(INFO)_vdm_dma_written:block overwritten on addr %d\n", sd_write_head);			
#endif
		}
	}
	while(!QUEUE_EMPTY(temp)){ //write back
		QUEUE_GET_FIRST(temp, b);
		QUEUE_ADD_LAST(pagedOutQueue, b);
	}

	//update history
	_vdm_update_history(paging_block, sd_write_head);

	//SD card ring: next
	sd_write_head = (sd_write_head+1)&SD_BIT_MASK;

	//appent element on the head
	if(QUEUE_FULL(pagedOutQueue)){
#ifdef VDM_DEBUG
		printf("(ERR)_vdm_dma_written:QUEUE_FULL(pagedOutQueue)\n");			
#endif		
		return;
	}
	QUEUE_ADD_LAST(pagedOutQueue, paging_block); //back on stack
	VDM_RESERVE; 

#ifdef VDM_DEBUG
	vdm_invariant(false);
#endif


	//more paging?
	if(STACK_EMPTY(pagedInStack)){
		return; //nothing to pageout
		//SD card full?
	}else if(((sd_write_head+1)&SD_BIT_MASK) == sd_read_head){
#ifdef VDM_DEBUG
		printf("(WARN)_vdm_dma_written:sd card full\n");			
#endif
		return;
	}
	else if(multipage)
		mutex_lock(MUTEX_DMA, _vdm_mtx_pageout);
}

/**
* @brief reads blocks from SD card, as long as paged out blocks
*        and empty RAM blocks are available
*/
void vdm_pagein(){

PAGEIN_OPT: //optimization label

	//empty block available?
	if(QUEUE_EMPTY(pagedOutQueue)){
#ifdef VDM_DEBUG
		printf("(WARN)vdm_pagein:memory full\n");			
#endif
		return; //not enough memory
	}

	//block on SD card?
	else if(sd_read_head == sd_write_head){
#ifdef VDM_DEBUG
		printf("(INFO)vdm_pagein:SD card empty\n");			
#endif
		return;//SD card empty
	}


	//pagein optimazation by moving the read head to the right
	QUEUE_GET_FIRST(pagedOutQueue, paging_block);
	if(paging_block->paged && paging_block->sd_address == sd_read_head){
		if(STACK_FULL(pagedInStack)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_pagein:STACK_FULL(pagedInStack)\n");	
#endif	
			return;
		}

		STACK_PUSH(pagedInStack, paging_block); //back on stack

		//SD card ring: next
		sd_read_head = (sd_read_head+1)&SD_BIT_MASK;

		//update history
		_vdm_update_history(paging_block, VDM_UNPAGED);

#ifdef VDM_DEBUG
		printf("(INFO)vdm_pagein: block pagin optimization by moving r\n");	
#endif	
		goto PAGEIN_OPT;
	}
	QUEUE_ADD_FIRST(pagedOutQueue, paging_block);

	//pagein optimazation by moving the write head to the left
	QUEUE_GET_LAST(pagedOutQueue, paging_block);
	uint16_t head = (sd_write_head-1)&SD_BIT_MASK;
	if(paging_block->paged && paging_block->sd_address == head){
		if(STACK_FULL(pagedInStack)){
#ifdef VDM_DEBUG
			printf("(ERR)vdm_pagein:STACK_FULL(pagedInStack)\n");	
#endif	
			return;
		}

		STACK_PUSH(pagedInStack, paging_block); //back on stack

		//SD card ring: next
		sd_write_head = head;

		//update history
		_vdm_update_history(paging_block, VDM_UNPAGED);

#ifdef VDM_DEBUG
		printf("(INFO)vdm_pagein: block pagin optimization by moving w\n");	
#endif	
		goto PAGEIN_OPT;
	}

	//no optimization
	QUEUE_ADD_LAST(pagedOutQueue, paging_block);

	mutex_lock(MUTEX_DMA, _vdm_mtx_pagein);
}

/**
* @brief callback function of mutex consumer, called when lock is possible
*/
void _vdm_mtx_pagein(enum mutex_dev device){

	uint16_t ret; 

	//empty block available? (could have changed)
	if(QUEUE_EMPTY(pagedOutQueue)){
#ifdef VDM_DEBUG
		printf("(WARN)_vdm_mtx_pagein:QUEUE_EMPTY(pagedOutQueue)\n");			
#endif
		return; //deficient mem
	}else{
		QUEUE_GET_FIRST(pagedOutQueue, paging_block);
		sd_address = ((uint32_t)sd_read_head) << sd_state.BlockLen_bit;

		ret = Sd_read_block((void*)paging_block->frames, sd_address, _vdm_dma_read);

		//paging error!
		if(ret != sd_state.BlockLen){
#ifdef VDM_DEBUG
			SD_LED_READ_ON;
			printf("(ERR)_vdm_mtx_pagein:Sd_write_block error %d\n",ret);			
#endif	
			mutex_unlock(MUTEX_DMA);
			if(!(QUEUE_FULL(pagedOutQueue)) )
				QUEUE_ADD_FIRST(pagedOutQueue, paging_block); //back on stack
			else{
#ifdef VDM_DEBUG
				printf("(ERR)_vdm_mtx_pagein:QUEUE_FULL(pagedOutQueue)\n");			
#endif
				return;
			}
		}
	}
}


/**
* @brief function called when DMA read process finished
* @author andi
*
* @param  ret Number of bytes read (should always be = sd_state.BlockLen)
*/
void _vdm_dma_read(uint16_t ret){

#ifdef VDM_DEBUG
	//printf("(INFO)_vdm_dma_read:block paged from address %d\n", sd_read_head);			
#endif
	//temporally unlock mutex for fairness
	mutex_unlock(MUTEX_DMA);

	paging_block->dirty = false;
	paging_block->sd_address = sd_read_head;

	//check frames here
	paging_block->num_frames = 4;

	//SD card ring: next
	sd_read_head = (sd_read_head+1)&SD_BIT_MASK;

	//back on stack
	if(STACK_FULL(pagedInStack) ){// error!!!
#ifdef VDM_DEBUG
		printf("(ERR)_vdm_dma_read:STACK_FULL(pagedInStack)\n");			
#endif	
		return;
	}
	else
		STACK_PUSH(pagedInStack, paging_block); 

#ifdef VDM_DEBUG
	vdm_invariant(false);
#endif

	//update history
	_vdm_update_history(paging_block, VDM_UNPAGED);

	//more paging?
	if(sd_write_head == sd_read_head){
#ifdef VDM_DEBUG
		printf("(INFO)_vdm_dma_read:SD card empty\n");			
#endif
		return; //nothing to pagein
	}
	else if(QUEUE_EMPTY(pagedOutQueue)){
#ifdef VDM_DEBUG
		//printf("(WARN)_vdm_dma_read:memory full\n");			
#endif
		return;//deficient RAM
	}

	mutex_lock(MUTEX_DMA, _vdm_mtx_pagein);
}

/**
* @brief checks all blocks in stacks and queue, whether they are valid
*/
#endif

#ifdef VDM_DEBUG
#define VDM_BLOCK_NUMBER(b,i) do{ \
	for(i=0; i<NUM_RAM_BLOCKS; i++) \
	if((&vdm_buffer[i]) == b) break;\
}while(0)


void vdm_invariant(bool verbose){
	uint8_t c[NUM_RAM_BLOCKS];

	//init
	uint8_t i;
	for(i=0; i<NUM_RAM_BLOCKS; i++ )
		c[i]=0;

	uint8_t j = 0;
	if(verbose)printf("empty blocks:\n");
	//queue
	for(i=pagedOutQueue.head; i!=pagedOutQueue.tail; i=((i+1)&QUEUE_MASK)){
		VDM_BLOCK_NUMBER(pagedOutQueue.buffer[i],j);
		c[j]++;
		if(verbose)printf(" %d\n", j);
	}

	if(verbose)printf("partly filled blocks:\n");
	//stack1
	for(i=0; i<fragmentStack.sp; i++){
		VDM_BLOCK_NUMBER(fragmentStack.buf[i],j);
		c[j]++;
		if(verbose)printf(" %d\n", j);
	}
	if(verbose)printf("full blocks:\n");
	//stack1
	for(i=0; i<pagedInStack.sp; i++){
		VDM_BLOCK_NUMBER(pagedInStack.buf[i],j);
		c[j]++;
		if(verbose)printf(" %d\n", j);
	}

#ifdef SENSOR
	if(verbose)printf("reserved blocks:\n");
	//reserved
	if(vdm_reserved){
		VDM_BLOCK_NUMBER(vdm_reserved,j);
		c[j]++;
	}
#endif
	if(verbose)printf(" %d\n", j);
	//check
	for(i=0; i<NUM_RAM_BLOCKS; i++ ){
		if(!(c[i]==0 && vdm_buffer[i].locked) && (c[i]!=1))
			printf("(ERR)VDM invariant injured!\n");
	}
}

/**
* @brief prints the sizes of all queues and stacks
*/
void vdm_printStatus(){

	//blocks allocated
	uint8_t alloc = 0; 
	uint8_t i;
	for(i=0; i<NUM_RAM_BLOCKS; i++)
		if(vdm_buffer[i].locked) alloc++;
	printf("VDM %d allocated blocks\n", alloc);

#ifdef SENSOR
	if(vdm_reserved)
		printf("VDM 1 reserved block\n");
	else
		printf("VDM 0 reserved block\n");
#endif
	printf("VDM %d empty blocks\n", (pagedOutQueue.tail - pagedOutQueue.head)&QUEUE_MASK);
	printf("VDM %d partly filled blocks\n", fragmentStack.sp);
	printf("VDM %d full blocks\n", pagedInStack.sp);

#ifdef SDCARD
	printf("VDM %d blocks on SD card\n", (sd_write_head-sd_read_head)&SD_BIT_MASK);
	printf("VDM rHead->%d wHead->%d\n", sd_read_head, sd_write_head);
#endif
	vdm_invariant(false);
}
#endif

#ifdef SDCARD
///< updates history for reacently paged segments
void _vdm_update_history(sd_block_t* b, uint16_t sd_addr){

	uint8_t i;

	//find block_idx
	uint8_t block_idx=0;
	for(i=0; i<NUM_RAM_BLOCKS; i++){
		if(b == &(vdm_buffer[i])){
			block_idx = i;
			break;
		}
	}

	for(i=0; i<NUM_FRAMES; i++){

		//segment empty?
		if(b->frames[i].decoded.nwh.size == 0) 
			continue;

		history_entry_t* e= &(history[HASH(b->frames[i].decoded.payload.seg.key.raw)]);

		//pagein?
		if(sd_addr == VDM_UNPAGED){

			//segment still in history?
			if(e->id.raw == b->frames[i].decoded.payload.seg.key.raw){

				//meanwhile confirmed?
				if(e->info.properties.confirmed){
					vdm_remove_frame(block_idx, i);
#ifdef VDM_DEBUG
					printf("(INFO)_vdm_update_history: removing confirmed segment %u from block %d.\n",e->id.raw,block_idx);
#endif
				}
				else{
					e->info.properties.block_idx = block_idx;
					e->info.properties.frame_idx = i;
					e->info.properties.paged = false;
				}
			}
			//overwrite entry if unlocked
			else if(e->info.properties.paged || e->info.properties.confirmed){
				e->id.raw = b->frames[i].decoded.payload.seg.key.raw;
				e->info.properties.block_idx = block_idx;
				e->info.properties.frame_idx = i;
				e->info.properties.confirmed = false;
				e->info.properties.paged = false;
			}
#ifdef VDM_DEBUG
			else
				printf("(WARN)_vdm_update_history:paged in segment %u not added to history (locked by %u)\n", b->frames[i].decoded.payload.seg.key.raw, e->id.raw);			
#endif	
		}else{//pageout
			//verify that entry is not used by different segment
			if(e->id.raw == b->frames[i].decoded.payload.seg.key.raw){
				//e->info.properties.block_idx = HISTORY_UNBUFFERED;
				e->info.sd.sd_address = sd_addr;
				e->info.properties.paged = true;
			}
		}
	}
}
#endif

/**
* @brief removes frame from block and updates block management 
* @param block		block contains frame
* @param frame_idx index of frame
*/
void vdm_remove_frame(uint8_t block_idx, uint8_t frame_idx){

	dint();

	sd_block_t* block = (sd_block_t*)&(vdm_buffer[block_idx]);

	//if(((uint16_t)block & 1) || ((uint16_t)&(block->frames[frame_idx]) & 1))
	//	printf("ADDRESS ERROR %u, %u\n", block, &(block->frames[frame_idx]));

	//clear frame
	block->frames[frame_idx].decoded.crc = 0; 
	block->frames[frame_idx].decoded.nwh.size = 0;
	block->frames[frame_idx].decoded.payload.seg.key.raw = 0;

	QUEUE(temp);

	QUEUE_INIT(temp);
	sd_block_t* b;
	//remove frome pagedInStack
	//printf("sp=%d size = %d [%d]=",pagedInStack.sp, block->num_frames, block);
	if(block->num_frames == NUM_FRAMES){
		//printf("searching...");
		//dissipate stack
		while(!STACK_EMPTY(pagedInStack)){ 
			STACK_POP(pagedInStack, b);
			//printf("(%d)", b);
			if(block != b)
				QUEUE_ADD_LAST(temp, b);
			else{
				//printf(" removed.\n");
				STACK_PUSH(fragmentStack, block);//insert block
			}
		}
		while(!QUEUE_EMPTY(temp)){//write back
			QUEUE_GET_LAST(temp, b);
			STACK_PUSH(pagedInStack, b);
		}


	}
	//remove from fragmentStack
	else if(block->num_frames == 1){
		//dissipate stack
		while(!STACK_EMPTY(fragmentStack)){ 
			STACK_POP(fragmentStack, b);
			if(block != b)
				QUEUE_ADD_LAST(temp, b);
			else{
				QUEUE_ADD_LAST(pagedOutQueue, block);//insert block
				VDM_RESERVE;
			}
		}
		while(!QUEUE_EMPTY(temp)){//write back
			QUEUE_GET_LAST(temp, b);
			STACK_PUSH(fragmentStack, b);
		}
	}
	block->num_frames--;
}



